
import java.util.InputMismatchException;
import java.util.Scanner;

public class ExceptionTest {
    //在Java中 异常分为三种类型:
    //1.受检查异常(Checked Exception): 在方法声明中必须声明抛出的异常 否则编译不通过
    //  这种异常是由于程序外部条件导致的 因此程序员应该能够处理这类异常情况 例如 文件读取时可能发生IO异常
    //2.不受检查异常(Unchecked Exception): 也称为运行时异常(Runtime Exception)
    //  不需要在方法声明中声明 编译时也不会出错 这种异常通常是由程序内部错误导致的 比如数组越界 空指针异常等
    //3.错误(Error): 与异常不同 错误是指JVM无法解决的严重问题 例如
    //  OutOfMemoryError StackOverflowError 等 程序无法用程序来处理这类错误

    public static void main(String[] args) {
        //自定义异常类

    }

    public static void main4(String[] args) {
        //finally 始终会执行的部分

        /*Scanner scanner = new Scanner(System.in);
        try {
            int in = scanner.nextInt();
            System.out.println(in);
        } catch (InputMismatchException e) {
            e.printStackTrace();
            System.out.println("输入类型不匹配!");
        } finally {//finally 中常用来书写关闭所调用的代码
            scanner.close();
        }*/

        //上述代码可简化为：
        try (Scanner scanner = new Scanner(System.in)) {//此时try 会自动关闭使用了的资源
            int in = scanner.nextInt();
            System.out.println(in);
        } catch (InputMismatchException e) {
            e.printStackTrace();
            System.out.println("输入类型不匹配!");
        }
        /*
         * jj
         * java.util.InputMismatchException
         * 	at java.base/java.util.Scanner.throwFor(Scanner.java:939)
         * 	at java.base/java.util.Scanner.next(Scanner.java:1594)
         * 	at java.base/java.util.Scanner.nextInt(Scanner.java:2258)
         * 	at java.base/java.util.Scanner.nextInt(Scanner.java:2212)
         * 	at ExceptionTest.main(ExceptionTest.java:31)
         * 输入类型不匹配!
         *
         * 进程已结束，退出代码为 0
         */

        //即使在 finally 前执行了 return 语句 finally 中的代码依旧会被执行
        //finally 中不应该出现 return 语句(如若出现 则返回值 以 finally 中的为准
    }

    public static void meth2(int a) throws NoSuchFieldException {
        if (a == 0) {
            throw new NoSuchFieldException();
        }
    }

    public static void main3(String[] args) throws NoSuchFieldException {
        //throws 声明异常
        //当我们在某个方法中可能会抛出某个受查异常 (也可以声明非受查异常 但当只有非受查异常时可不写声明)
        //但又不想处理时可用 throws 来声明异常
        //注意: 调用这个方法的使用者应该处理声明了的异常 如果调用者也只声明异常 则异常 会由jvm来处理
        //     但此时的异常便失去了意义 因为交给jvm后程序就会在异常处终止执行了
        meth2(0);
        System.out.println("位于异常后的代码");

        /*
         * Exception in thread "main" java.lang.NoSuchFieldException
         * 	at ExceptionTest.meth2(ExceptionTest.java:14)
         * 	at ExceptionTest.main(ExceptionTest.java:24)
         *
         * 进程已结束，退出代码为 1
         */

    }

    //返回 a 数组中 pos 下标处的数 除以 n 的结果
    public static int meth1(int[] a, int pos, int n) {
        if (a == null) {
            System.out.println("meth1 中 当 a==null 时 meth1 将会运行的代码");
            throw new NullPointerException();
            //不能在抛出异常的语句后添加语句 因为位于抛出异常后的代码将不可能被执行
        }
        if (pos < 0 || pos >= a.length) {
            System.out.println("meth1 中 当 pos < 0 || pos >= a.length 时 meth1 将会运行的代码");
            throw new IndexOutOfBoundsException();
        }
        if (n == 0) {
            System.out.println("meth1 中 当 n==0 时 meth1 将会运行的代码");
            throw new ArithmeticException();
        }

        System.out.println("未发生异常 meth1 将会运行的代码");
        return a[pos] / n;
    }

    public static void main2(String[] args) {
        //throw 抛出异常
        try {
            int ret = meth1(null, 0, 1);
            System.out.println("meth1 未发生异常 main try 中将会运行的代码");
            System.out.println(ret);
        } catch (NullPointerException e) {
            e.printStackTrace();
            System.out.println("catch NullPointerException 捕获到异常 main catch(NullPointerException e) 将会执行的代码");
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("catch IndexOutOfBoundsException 捕获到异常 main catch(IndexOutOfBoundsException e) 将会执行的代码");
        } catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("catch ArithmeticException 捕获到异常 main catch(ArithmeticException e) 将会执行的代码");
        }
        System.out.println("main 中 try catch 后将会执行的代码");

        System.out.println();
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        try {
            int[] nums = {1, 2, 3};
            int ret = meth1(nums, 3, 1);
            System.out.println("meth1 未发生异常 main try 中将会运行的代码");
            System.out.println(ret);
        } catch (NullPointerException e) {
            e.printStackTrace();
            System.out.println("catch NullPointerException 捕获到异常 main catch(NullPointerException e) 将会执行的代码");
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("catch IndexOutOfBoundsException 捕获到异常 main catch(IndexOutOfBoundsException e) 将会执行的代码");
        } catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("catch ArithmeticException 捕获到异常 main catch(ArithmeticException e) 将会执行的代码");
        }
        System.out.println("main 中 try catch 后将会执行的代码");

        System.out.println();
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        try {
            int[] nums = {1, 2, 3};
            int ret = meth1(nums, 2, 0);
            System.out.println("meth1 未发生异常 main try 中将会运行的代码");
            System.out.println(ret);
        } catch (NullPointerException e) {
            e.printStackTrace();
            System.out.println("catch NullPointerException 捕获到异常 main catch(NullPointerException e) 将会执行的代码");
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("catch IndexOutOfBoundsException 捕获到异常 main catch(IndexOutOfBoundsException e) 将会执行的代码");
        } catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("catch ArithmeticException 捕获到异常 main catch(ArithmeticException e) 将会执行的代码");
        }
        System.out.println("main 中 try catch 后将会执行的代码");

        System.out.println();
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        try {
            int[] nums = {1, 2, 3};
            int ret = meth1(null, 100, 0);
            System.out.println("meth1 未发生异常 main try 中将会运行的代码");
            System.out.println(ret);
        } catch (NullPointerException e) {
            e.printStackTrace();
            System.out.println("catch NullPointerException 捕获到异常 main catch(NullPointerException e) 将会执行的代码");
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("catch IndexOutOfBoundsException 捕获到异常 main catch(IndexOutOfBoundsException e) 将会执行的代码");
        } catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("catch ArithmeticException 捕获到异常 main catch(ArithmeticException e) 将会执行的代码");
        }
        System.out.println("main 中 try catch 后将会执行的代码");

        System.out.println();
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        try {
            int[] nums = {1, 2, 3};
            int ret = meth1(nums, 1, 1);
            System.out.println("meth1 未发生异常 main try 中将会运行的代码");
            System.out.println(ret);
        } catch (NullPointerException e) {
            e.printStackTrace();
            System.out.println("catch NullPointerException 捕获到异常 main catch(NullPointerException e) 将会执行的代码");
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("catch IndexOutOfBoundsException 捕获到异常 main catch(IndexOutOfBoundsException e) 将会执行的代码");
        } catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("catch ArithmeticException 捕获到异常 main catch(ArithmeticException e) 将会执行的代码");
        }
        System.out.println("main 中 try catch 后将会执行的代码");
        System.out.println();

        /*
         * meth1 中 当 a==null 时 meth1 将会运行的代码
         * catch NullPointerException 捕获到异常 main catch(NullPointerException e) 将会执行的代码
         * main 中 try catch 后将会执行的代码
         *
         * meth1 中 当 pos < 0 || pos >= a.length 时 meth1 将会运行的代码
         * catch IndexOutOfBoundsException 捕获到异常 main catch(IndexOutOfBoundsException e) 将会执行的代码
         * main 中 try catch 后将会执行的代码
         *
         * meth1 中 当 n==0 时 meth1 将会运行的代码
         * catch ArithmeticException 捕获到异常 main catch(ArithmeticException e) 将会执行的代码
         * main 中 try catch 后将会执行的代码
         *
         * meth1 中 当 a==null 时 meth1 将会运行的代码
         * catch NullPointerException 捕获到异常 main catch(NullPointerException e) 将会执行的代码
         * main 中 try catch 后将会执行的代码
         *
         * 未发生异常 meth1 将会运行的代码
         * meth1 未发生异常 main try 中将会运行的代码
         * 2
         * main 中 try catch 后将会执行的代码
         *
         * java.lang.NullPointerException
         * 	at ExceptionTest.meth1(ExceptionTest.java:14)
         * 	at ExceptionTest.main(ExceptionTest.java:33)
         * java.lang.IndexOutOfBoundsException
         * 	at ExceptionTest.meth1(ExceptionTest.java:19)
         * 	at ExceptionTest.main(ExceptionTest.java:52)
         * java.lang.ArithmeticException
         * 	at ExceptionTest.meth1(ExceptionTest.java:23)
         * 	at ExceptionTest.main(ExceptionTest.java:71)
         * java.lang.NullPointerException
         * 	at ExceptionTest.meth1(ExceptionTest.java:14)
         * 	at ExceptionTest.main(ExceptionTest.java:90)
         *
         * 进程已结束，退出代码为 0
         */

        //从上面的代码中我们可以看出:
        //meth1 中抛出异常后的代码 将不会被执行
        //当我们可能会触发多个异常时 他只会抛出第一个异常 原因就是刚说过的 meth1 中抛出异常后的代码 将不会被执行
        //当我们用 e.printStackTrace(); 来处理异常时 他只会输出 源代码中触发异常的代码所在的行 以及异常类型
        //有些jvm 会显示的提示信息 没了
        //输出的异常信息在程序的最后
    }

    public static void main1(String[] args) {
        //try catch 处理异常
        try {
            System.out.println(10 / 0);

            int[] nums = {1, 2, 3};
            System.out.println(nums[10]);

            nums = null;
            System.out.println(nums.length);

            System.out.println("try 中 异常后的代码");
        } catch (NullPointerException e) {
            e.printStackTrace();
            System.out.println("catch NullPointerException 中 e.printStackTrace() 后的代码");
        } catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("catch ArithmeticException 中 e.printStackTrace() 后的代码");
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("catch IndexOutOfBoundsException 中 e.printStackTrace() 后的代码");
        }
        System.out.println("try catch 后的代码");
        /*
         * java.lang.ArithmeticException: / by zero
         * 	at ExceptionTest.main(ExceptionTest.java:13)
         * catch ArithmeticException 中 e.printStackTrace() 后的代码
         * try catch 后的代码
         *
         * 进程已结束，退出代码为 0
         */
        //上述代码表面try catch 处理异常时:
        //当有异常被 catch 捕获到时 try 中的代码将不会继续执行
        //而会转到相应 catch 并执行其中的代码
        //由于 try 中 位于第一个异常后的代码 都不被执行 故不会 在一个 try 中触发多个异常

        //try 后的代码 依旧执行
    }
}
